//
// Created by wxd on 2025/9/11.
//

#pragma once

#ifndef MATERIAL_H
#define MATERIAL_H

#include "IMaterial.h"

class Material : public IMaterial {
public:

    ~Material() override = default;

    std::string getTraceId() override { return mTraceId; }
    std::string getName() override { return mMaterialName; }
    MaterialType getType() override { return mType; }
    EngineMaterialParam::CullParams getCullParams() override { return mCullParams; }
    EngineMaterialParam::BlendParams getBlendParams() override { return mBlendParams; }
    EngineMaterialParam::DepthParams getDepthParams() override { return mDepthParams; }
    EngineMaterialParam::StencilParams getStencilParams() override { return mStencilParams; }
    void loadShader(const std::string &vertPath, const std::string &fragPath) override;
    std::unique_ptr<Shader> getShader() override { return std::move(mShader); }

    void bind() override;

    template<typename T>
    void uniform(const std::string &name, const T& value) {
        if (mShader) {
            mShader->setUniform(name, value);
        }
    }
    void uniform(const std::string &name, const UniformValue &value) override;
    void uniforms(const std::unordered_map<std::string, UniformValue> &values) override;
    void unbind() override;

    virtual void setDepthParams(const EngineMaterialParam::DepthParams& params) { mDepthParams = params; }
    virtual void setStencilParams(const EngineMaterialParam::StencilParams& params) { mStencilParams = params; }
    virtual void setBlendParams(const EngineMaterialParam::BlendParams& params) { mBlendParams = params; }
    virtual void setCullParams(const EngineMaterialParam::CullParams& params) { mCullParams = params; }

    virtual void setTraceId(const std::string& id) { mTraceId = id; }
    virtual void setName(const std::string& name) { mMaterialName = name; }
    virtual void setType(const MaterialType type) { mType = type; }
    virtual void setShader(std::unique_ptr<Shader> shader) { mShader = std::move(shader); }

protected:
    Material() : mMaterialName("Material"), mType(MaterialType::NONE) {
        mTraceId = IDGenerator::getInstance().generateString(IDPrefix::MATERIAL);
    }

    Material(const std::string& name, const MaterialType type) : mMaterialName(name), mType(type) {
        mTraceId = IDGenerator::getInstance().generateString(IDPrefix::MATERIAL);
    }

    EngineMaterialParam::DepthParams mDepthParams {};
    EngineMaterialParam::StencilParams mStencilParams {};
    EngineMaterialParam::BlendParams mBlendParams {};
    EngineMaterialParam::CullParams mCullParams {};

    std::string mMaterialName { "Material" };
    std::string mTraceId;
    MaterialType mType { MaterialType::NONE };
    std::unique_ptr<Shader> mShader {};
};

#endif //MATERIAL_H
